#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "shmem.h"
#include "cJSON.h"
#include "MQTTClient.h"

#define ADDRESS "tcp://mqtt.yyzlab.com.cn"
#define CLIENTID "metaClientPub"
#define TOPIC_PUB "3220772638/Device2AIOTSIM"
#define QOS 1
#define TIMEOUT 10000L

// 定义共享内存结构体
union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};

struct std_node
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};

int main(int argc, char const *argv[])
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc;
    if ((rc = MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to create client, return code %d\n", rc);
        exit(EXIT_FAILURE);
    };
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    // 连接MQTT服务器
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }

    struct shm_param para;
    if (shm_init(&para, "data", 1024) < 0)
    {
        printf("shm init err\n");
        MQTTClient_disconnect(client, 10000);
        MQTTClient_destroy(&client);
        exit(EXIT_FAILURE);
    }

    int *p = NULL; // 映射后的起始地址
    // 映射共享内存
    p = shm_getaddr(&para); // 获取共享内存地址
    if (!p)
    {
        fprintf(stderr, "shm getaddr error\n");
        MQTTClient_disconnect(client, 10000);
        MQTTClient_destroy(&client);
        exit(EXIT_FAILURE);
    }
    int node_count = *p;
    //  共享内存首地址是结构体节点个数
    struct std_node *data_p = (struct std_node *)(p + 1);
    // 循环读取数据并发布
    while (1)
    {
        cJSON *root = cJSON_CreateObject();
        struct std_node *tmp_std = NULL;
        for (int j = 0; j < node_count; j++)
        {
            tmp_std = data_p + j;

            if (tmp_std->key == 101)
            {
                cJSON_AddItemToObject(root, "tem", cJSON_CreateNumber(tmp_std->new_val.f_val));
            }

            if (tmp_std->key == 102)
            {
                cJSON_AddItemToObject(root, "hum", cJSON_CreateNumber(tmp_std->new_val.f_val));
            }

            if (tmp_std->key == 103)
            {
                cJSON_AddItemToObject(root, "fire", cJSON_CreateBool(tmp_std->new_val.b_val));
            }

            if (tmp_std->key == 104)
            {
                cJSON_AddItemToObject(root, "infrared", cJSON_CreateBool(tmp_std->new_val.b_val));
            }

            if (tmp_std->key == 106)
            {
                cJSON_AddItemToObject(root, "irrigated", cJSON_CreateBool(tmp_std->new_val.b_val));
            }

            if (tmp_std->key == 107)
            {
                cJSON_AddItemToObject(root, "fan", cJSON_CreateBool(tmp_std->new_val.b_val));
            }

            if (tmp_std->key == 108)
            {
                cJSON_AddItemToObject(root, "alarm", cJSON_CreateBool(tmp_std->new_val.b_val));
            }

            if (tmp_std->key == 201)
            {
                cJSON_AddItemToObject(root, "doorLock", cJSON_CreateBool(tmp_std->new_val.b_val));
            }
            // 单独处理105（lamp id=0）
            if (tmp_std->key == 105)
            {
                cJSON *root_lamp = cJSON_CreateObject();
                cJSON_AddItemToObject(root_lamp, "lamp", cJSON_CreateBool(tmp_std->new_val.b_val));
                cJSON_AddItemToObject(root_lamp, "id", cJSON_CreateString("0"));
                pubmsg.payload = cJSON_Print(root_lamp);
                pubmsg.payloadlen = (int)strlen(cJSON_Print(root_lamp));
                pubmsg.qos = QOS;
                pubmsg.retained = 0;
                MQTTClient_publishMessage(client, TOPIC_PUB, &pubmsg, &token);
                printf("%s\n", pubmsg.payload);
                cJSON_Delete(root_lamp);
            }
            // 单独处理109（lamp id=1）
            if (tmp_std->key == 109)
            {
                cJSON *root_lamp = cJSON_CreateObject();
                cJSON_AddItemToObject(root_lamp, "lamp", cJSON_CreateBool(tmp_std->new_val.b_val));
                cJSON_AddItemToObject(root_lamp, "id", cJSON_CreateString("1"));
                pubmsg.payload = cJSON_Print(root_lamp);
                pubmsg.payloadlen = (int)strlen(cJSON_Print(root_lamp));
                pubmsg.qos = QOS;
                pubmsg.retained = 0;
                MQTTClient_publishMessage(client, TOPIC_PUB, &pubmsg, &token);
                printf("%s\n", pubmsg.payload);
                cJSON_Delete(root_lamp);
            }
        }
        pubmsg.payload = cJSON_Print(root);
        pubmsg.payloadlen = (int)strlen(cJSON_Print(root));
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        MQTTClient_publishMessage(client, TOPIC_PUB, &pubmsg, &token);
        printf("%s\n", pubmsg.payload);
        cJSON_Delete(root);

        sleep(1);
    }

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return 0;
}
